/*
PearReview - The peer review assistant.
Copyright (C) 2009  Dimitrij Pankratz, Anton Musichin
http://www.pearreview.com, info@pearreview.com

This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
*/

package com.pearreview.moderatorplugin;

import java.awt.Color;
import java.awt.Component;
import java.awt.Toolkit;
import java.awt.event.ActionEvent;
import java.awt.event.KeyEvent;
import java.io.File;
import java.io.Serializable;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Formatter;

import javax.swing.AbstractAction;
import javax.swing.Action;
import javax.swing.Icon;
import javax.swing.ImageIcon;
import javax.swing.JComponent;
import javax.swing.JFileChooser;
import javax.swing.JOptionPane;
import javax.swing.JScrollPane;
import javax.swing.JSplitPane;
import javax.swing.KeyStroke;
import javax.swing.event.ListSelectionEvent;
import javax.swing.event.ListSelectionListener;

import com.pearreview.ui.StepTabs;
import com.pearreview.ui.TipButton;
import com.pearreview.application.Messages;
import com.pearreview.application.PluginAdapter;
import com.pearreview.application.SaveData;
import com.pearreview.util.XMLFileFilter;
import com.pearreview.util.review.Review;
import com.pearreview.util.review.io.ReviewReader;
import com.pearreview.util.review.io.ReviewWriter;
import com.pearreview.util.review.io.XMLReviewReader;
import com.pearreview.util.review.io.XMLReviewWriter;

public class ModeratorView implements ModeratorReviewFormValidator, 
		Serializable {
	private static final long serialVersionUID = 2942190092107011163L;
	
	private static final String XML_PREFIX = "PearReview";
	
	public static final String FILE_HISTORY_TYPE = "review-xml";
	
	private PluginAdapter pluginAdapter;	
	
	private JSplitPane splitPane;
	private StepTabs stepTabs;
	private String[] steps = {
			getLocalizedString("tabs.start"),
			getLocalizedString("tabs.information"),
			getLocalizedString("tabs.meetings"),
			getLocalizedString("tabs.aspects"),
			getLocalizedString("tabs.attendees"),
			getLocalizedString("tabs.distribute"),
			getLocalizedString("tabs.severities"),
			getLocalizedString("tabs.invitations")};
	
	/* actions */
	private Action nextViewAction = new NextViewAction();
	private Action previousViewAction = new PreviousViewAction();
	private Action firstViewAction = new FirstViewAction();
	private Action openReviewAction = new OpenReviewAction();
	private Action openReviewFileAction = new OpenReviewFileAction();
	private Action newReviewAction = new NewReviewAction();
	private Action saveReviewAction = new SaveReviewAction();
	private Action saveAsReviewAction = new SaveAsReviewAction();
	private Action openCatalogManagerAction = new OpenCatalogManagerAction();
	private Action navigateToHomeAction = new NavigateToHomeAction();
	
	
	private JScrollPane mainScrollPane = new JScrollPane();
	private TipButton hintBtn;
	private int currentView = -1;
	
	/* view panels */
	private StartPanel startPanel;
	private InformationPanel informationPanel;
	private MeetingsPanel meetingsPanel;
	private AspectsPanel aspectsPanel;
	private AttendeePanel attendeePanel;
	private DistributerPanel distributerPanel;
	private SeverityPanel severityPanel;
	private InvitationsPanel invitationsPanel;
	
	private Component[] views = {};
	
	/**
	 * the current review file (<code>null</code> if review is unsaved)
	 */
	private File reviewFile = null;
	
	/**
	 * If the user has to choose for open a review or a new review.
	 * Before choosing one of this two options, no next view available.
	 */
	private boolean startMode = true;
	
	public ModeratorView(PluginAdapter pluginAdapter) {
		this.pluginAdapter = pluginAdapter;
		initComponents();
		this.setStartMode(true);
	}
	
	/**
	 * Returns default review file.
	 * @return default review file
	 */
	public static File getDefaultSaveAsFile() {
		return new File("review_" + 
				new SimpleDateFormat("dd.MM.yyyy").format(new Date()));
	}
	
	/**
	 * Returns localized string of this component
	 * @param key key of string to localize
	 * @return localized string of this component
	 */
	private static String getLocalizedString(String key) {
		return Messages.getString("PearReview.Moderator." + key);
	}
	
	public Action getNextViewAction() {
		return nextViewAction;
	}
	
	public Action getPreviousViewAction() {
		return previousViewAction;
	}
	
	public Action getFirstViewAction() {
		return firstViewAction;
	}
	
	public Action getOpenReviewAction() {
		return openReviewAction;
	}
	
	public Action getNewReviewAction() {
		return newReviewAction;
	}
	
	public Action getSaveReviewAction() {
		return saveReviewAction;
	}
	
	public Action getSaveAsReviewAction() {
		return saveAsReviewAction;
	}
	
	public Action getOpenCatalogManagerAction() {
		return openCatalogManagerAction;
	}
	
	public Action getNavigateToHomeAction() {
		return navigateToHomeAction;
	}
	
	private void setStartMode(boolean startMode) {
		this.startMode = startMode;
		if (startMode) {
			stepTabs.setMaxSelectionIndex(0);
		} else {
			stepTabs.setMaxSelectionIndex(-1);
		}
		updateActions();
	}
	
	/**
	 * Sets the button to show hints for current panel. 
	 * 
	 * @param hintBtn
	 */
	public void setTipBtn(TipButton hintBtn) {
		this.hintBtn = hintBtn;
		
		int index = stepTabs.getSelectedIndex();
		index = Math.max(index, 0);
		updateTip(index);
	}
	
	/**
	 * Sets the hint from current panel to the hint button.
	 */
	private void updateTip(int index) {
		if (hintBtn != null) {
			ModeratorPanel panel = (ModeratorPanel)views[index];
			hintBtn.setTipText(panel.getHint());
		}
	}
	
	private void updateActions() {
		int selected = stepTabs.getSelectedIndex();
		int max = Math.max(stepTabs.getMaxSelectionIndex(), views.length - 1);
		nextViewAction.setEnabled(selected < max);
		
		if (selected == 0) {
			previousViewAction.setEnabled(false);
			firstViewAction.setEnabled(false);
		} else {
			previousViewAction.setEnabled(true);
			firstViewAction.setEnabled(true);
		}
	}
	
	public void setView(int index) {
		stepTabs.setSelectedIndex(index);
	}
	
	public int getSizeView() {
		return views.length;
	}
	
	public void setNextView() {
		stepTabs.setSelectedIndex(stepTabs.getSelectedIndex() + 1);
	}
	
	public void setPreviousView() {
		stepTabs.setSelectedIndex(stepTabs.getSelectedIndex() - 1);
	}
	
	public Component getPanel() {
		return mainScrollPane;
	}
	
	/**
	 * Marks the last tab as checked or with an error.
	 * 
	 * @param index
	 */
	private void checkTab(int index) {
		if(index < 0)
			return;
		ModeratorPanel panel = (ModeratorPanel)views[index];
		
		if (panel.isValidForm()) {
			stepTabs.setTabChecked(index);
			stepTabs.setToolTipTab(null, index);
		} else {
			stepTabs.setTabError(index);
			stepTabs.setToolTipTab(panel.getErrorMessage(), index);
		}
	}
	
	private void updateView() {
		if(currentView == stepTabs.getSelectedIndex())
			return;
		
		int divederLoc;
		//set only first time and save then the position
		//after tab changing
		if (splitPane.getDividerLocation() == -1) {
			divederLoc = 180;
		} else {
			divederLoc = splitPane.getDividerLocation();
		}
		
		int index = stepTabs.getSelectedIndex();
		index = Math.max(index, 0);
		if (currentView != index)
			checkTab(currentView);
		currentView = index;
		
		splitPane.setRightComponent(views[index]);
		splitPane.setDividerLocation(divederLoc);
		
		//set hint
		updateTip(index);
		
		updateActions();
		
		if(views[index] == invitationsPanel) {
			invitationsPanel.setReview(getReview());
		}
	}
	
	private void initComponents() {
		startPanel = new StartPanel(pluginAdapter,
				newReviewAction, 
				openReviewAction,
				openReviewFileAction);
		
		views = new JComponent[]{startPanel};
		
		splitPane = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT);
		splitPane.setContinuousLayout(true);
		splitPane.setBackground(new Color(0xd6d6d6));
		splitPane.setOneTouchExpandable(true);
		splitPane.setBorder(null);
		
		stepTabs = new StepTabs(steps);
		stepTabs.addListSelectionListener(new TabListener());
		stepTabs.setSelectedIndex(0);
		stepTabs.setMaxSelectionIndex(0);
		
		splitPane.setLeftComponent(stepTabs);
		
		mainScrollPane.setViewportView(splitPane);
		mainScrollPane.setBorder(null);
		updateView();
	}
	
	/**
	 * loads save data
	 * @param sd save data to load
	 */
	public void loadSaveData(SaveData sd) {
		if(sd instanceof ModeratorPluginSaveData) {
			ModeratorPluginSaveData mpsd = (ModeratorPluginSaveData)sd;
			
			reviewFile = (File) mpsd.getValue(
					ModeratorPluginSaveData.REVIEW_FILE_KEY);
			Review review = (Review) mpsd.getValue(
					ModeratorPluginSaveData.REVIEW_KEY);
			Integer view = (Integer) mpsd.getValue(
					ModeratorPluginSaveData.VIEW_KEY);
			Integer[] states = (Integer[]) mpsd.getValue(
					ModeratorPluginSaveData.VIEW_STATES_KEY);
			File imageFile = (File) mpsd.getValue(
					ModeratorPluginSaveData.IMAGE_FILE_KEY);
			Boolean isImageAdded = (Boolean) mpsd.getValue(
					ModeratorPluginSaveData.IS_IMAGE_ADDED_KEY);
			File exportFile = (File) mpsd.getValue(
					ModeratorPluginSaveData.EXPORT_FILE_KEY);
			Integer exportMethod = (Integer) mpsd.getValue(
					ModeratorPluginSaveData.EXPORT_METHOD_KEY);
			
			setReview(review);
			
			setStartMode(review == null);
			
			setView(view);
			
			stepTabs.setStates(states);
			for(int index = 0 ; index < states.length ; index++) {
				if(states[index] != StepTabs.UNCHECKED_STATE) {
					checkTab(index);
				}
			}
			
			if(reviewFile != null && review != null) {
				pluginAdapter.setTitle(reviewFile.getName(), 
						reviewFile.getAbsolutePath());
				pluginAdapter.setFile(reviewFile);
			} else if(review != null) {
				pluginAdapter.setTitle(getLocalizedString("start.new_file"), 
						getLocalizedString("start.new_file"));
			}
			
			if(invitationsPanel != null) {
				if(imageFile != null) {
					invitationsPanel.setImageFile(imageFile);
				}
				if(isImageAdded != null) {
					invitationsPanel.setImageAdded(isImageAdded);
				}
				if(exportFile != null) {
					invitationsPanel.setLastExportFile(exportFile);
				}
				if(exportMethod != null) {
					invitationsPanel.setExportMethod(exportMethod);
				}
			}
		}
	}
	
	/**
	 * Returns save data
	 * @return save data
	 */
	public ModeratorPluginSaveData getSaveData() {
		ModeratorPluginSaveData sd = new ModeratorPluginSaveData();
		
		sd.putValue(ModeratorPluginSaveData.REVIEW_KEY, 
				getReview());
		sd.putValue(ModeratorPluginSaveData.REVIEW_FILE_KEY, 
				reviewFile);
		sd.putValue(ModeratorPluginSaveData.VIEW_STATES_KEY, 
				stepTabs.getStates());
		sd.putValue(ModeratorPluginSaveData.VIEW_KEY, 
				stepTabs.getSelectedIndex());
		if(invitationsPanel != null) {
			sd.putValue(ModeratorPluginSaveData.IMAGE_FILE_KEY, 
					invitationsPanel.getImageFile());
			sd.putValue(ModeratorPluginSaveData.IS_IMAGE_ADDED_KEY, 
					invitationsPanel.isImageAdded());
			sd.putValue(ModeratorPluginSaveData.EXPORT_FILE_KEY, 
					invitationsPanel.getLastExportFile());
			sd.putValue(ModeratorPluginSaveData.EXPORT_METHOD_KEY, 
					invitationsPanel.getExportMethod());
		}
		
		return sd;
	}
	
	@Override
	public void validateReviewForm() {
		for (int i=0; i<views.length; i++) {
			checkTab(i);
		}
	}
	
	@Override
	public boolean isValidReviewForm() {
		for (int i=0; i<views.length; i++) {
			ModeratorPanel panel = (ModeratorPanel)views[i];
			if(!panel.isValidForm())
				return false;
		}
		
		return true;
	}
	
	private File getCatalogWorkspace() {
		if(pluginAdapter.getWorkspace() == null) {
			return null;
		}
		
		return new File(pluginAdapter.getWorkspace(), 
				CatalogManager.CATALOG_DIRECTORY);
	}
	
	private void setReview(Review r) {
		saveReviewAction.setEnabled(true);
		saveAsReviewAction.setEnabled(true);
		
		informationPanel = new InformationPanel();

		meetingsPanel = new MeetingsPanel();
		aspectsPanel = new AspectsPanel(pluginAdapter, getCatalogWorkspace());
		attendeePanel = new AttendeePanel();
		distributerPanel = new DistributerPanel();
		severityPanel = new SeverityPanel();
		invitationsPanel = 
				new InvitationsPanel(pluginAdapter.getSpringGlassPane());
		
		invitationsPanel.setReviewValidator(this);
		
		distributerPanel.setAttendeeSlideBoxPanel(
				attendeePanel.getAttendeeSlideBoxPanel());
		distributerPanel.setAspectsModel(aspectsPanel.getAspectsModel());
		aspectsPanel.setSimpleChangeListener(
				distributerPanel);		
		
		
		views = new JComponent[]{startPanel, informationPanel, meetingsPanel,
				aspectsPanel, attendeePanel, distributerPanel, severityPanel,
				invitationsPanel};
		
		setActionsToPanels();
		
		if(r == null)
			return;
		
		informationPanel.setReviewName(r.getName());
		informationPanel.setReviewDescription(r.getDescription());
		informationPanel.setReviewComments(r.getComments());
		informationPanel.setProduct(r.getProduct());
		
		meetingsPanel.setMeetings(r.getMeetings());
		
		aspectsPanel.setAspects(r.getAspects());
		distributerPanel.setAspectsModel(aspectsPanel.getAspectsModel());
		
		attendeePanel.setAttendees(r.getAttendees());
		
		severityPanel.setSeverities(r.getSeverities());
	}
	
	/**
	 * Sets the actions like nextView or previousView to the panels.
	 */
	private void setActionsToPanels() {
		for (int i=0; i<views.length; i++) {
			ModeratorPanel panel = (ModeratorPanel)views[i];
			panel.setNextViewAction(nextViewAction);
			panel.setPreviousViewAction(previousViewAction);
		}
		
	}
	
	private Review getReview() {
		if(startMode)
			return null;
		
		Review r = new Review();
		
		r.setName(informationPanel.getReviewName());
		r.setDescription(informationPanel.getReviewDescription());
		r.setComments(informationPanel.getReviewComments());
		r.setProduct(informationPanel.getProduct());
		
		r.setMeetings(meetingsPanel.getMeetings());
		
		r.setAspects(aspectsPanel.getAspects());
		
		r.setAttendees(attendeePanel.getAttendees());
		
		r.setSeverities(severityPanel.getSeverities());
		
		/* apply attendee aspects */
		distributerPanel.applyAttendeeAspects();
		
		r.setImpression("");
		r.setRecommendation("");
		
		return r;
	}
	
	/**
	 * Write review to file and shows error message if fails
	 * @param f write to this file
	 * @return <code>true</code> if no errors occurred, 
	 * otherwise <code>false</code>
	 */
	private boolean writeReview(File f) {
		try {
			pluginAdapter.getFileHistory().add(f, FILE_HISTORY_TYPE);
			ReviewWriter writer = new XMLReviewWriter(XML_PREFIX);
			Review r = getReview();
			writer.write(r, f);
			reviewFile = f;
			pluginAdapter.setTitle(reviewFile.getName(), 
					reviewFile.getAbsolutePath());
			pluginAdapter.setFile(reviewFile);
			return true;
		} catch(Throwable e) {
			String message = getLocalizedString("error.save.exception");
			String title = getLocalizedString("error.save.exception.title");
			Formatter formatter = new Formatter();
			formatter.format(message, e.getLocalizedMessage());
			pluginAdapter.getSpringGlassPane().setFaded(true);
			JOptionPane.showMessageDialog(this.mainScrollPane, 
						formatter.toString(), 
						title, 
						JOptionPane.ERROR_MESSAGE);
			pluginAdapter.getSpringGlassPane().setFaded(false);
		}
		
		return false;
	}
	
	private void validateReviewFormOnSave() {
		validateReviewForm();
		
		String message = getLocalizedString("error.save.validation");
		String title = getLocalizedString("error.save.validation.title");
		pluginAdapter.getSpringGlassPane().setFaded(true);
		JOptionPane.showMessageDialog(this.mainScrollPane, 
					message, 
					title, 
					JOptionPane.ERROR_MESSAGE);
		pluginAdapter.getSpringGlassPane().setFaded(false);
	}
	
	/**
	 * Save the review. if review was not saved before, 
	 * method <code>SaveAsReview</code> will be called
	 * 
	 * @return <code>true</code> if review was successful saved
	 */
	public boolean saveReview() {
		if(!isValidReviewForm()) {
			validateReviewFormOnSave();
			return false;
		}
		
		if(reviewFile == null)
			return saveAsReview();
		else
			return writeReview(reviewFile);
	}
	
	/**
	 * Show save under dialog, and save the current review to selected file
	 * by using method <code>writeReview</code>.
	 * @return <code>true</code> if review was saved, 
	 * otherwise <code>false</code>
	 */
	public boolean saveAsReview() {
		if(!isValidReviewForm()) {
			validateReviewFormOnSave();
			return false;
		}
		
		final JFileChooser saveDialog = new JFileChooser();
		saveDialog.setMultiSelectionEnabled(false);
		saveDialog.setAcceptAllFileFilterUsed(false);
		
		XMLFileFilter reviewFilter = new XMLFileFilter();
		saveDialog.setFileFilter(reviewFilter);
		
		saveDialog.setCurrentDirectory(reviewFile);
		saveDialog.setSelectedFile(
				reviewFile == null ? getDefaultSaveAsFile() : reviewFile);
		
		pluginAdapter.getSpringGlassPane().setFaded(true);
		int ret = saveDialog.showSaveDialog(mainScrollPane);
		pluginAdapter.getSpringGlassPane().setFaded(false);
			 
		if (JFileChooser.APPROVE_OPTION != ret)
			return false;
		
		File selectedFile = saveDialog.getSelectedFile();
		if(!reviewFilter.accept(selectedFile)) {
			String fileName = selectedFile.getName();
			fileName += XMLFileFilter.EXTENSION;
			selectedFile = new File(selectedFile.getParent(), fileName);
		}
		return writeReview(selectedFile);
	}
	
	public boolean readReview(File f) {
		try {
			ReviewReader reader = new XMLReviewReader();
			Review review = reader.read(f);
			pluginAdapter.getFileHistory().add(f, FILE_HISTORY_TYPE);
			setReview(review);
			setStartMode(false);
			setNextView();
			reviewFile = f;
			pluginAdapter.setTitle(reviewFile.getName(), 
					reviewFile.getAbsolutePath());
			pluginAdapter.setFile(reviewFile);
			return true;
		} catch(Throwable e) {
			String message = getLocalizedString("error.open.exception");
			String title = getLocalizedString("error.open.exception.title");
			Formatter formatter = new Formatter();
			formatter.format(message, e.getLocalizedMessage());
			pluginAdapter.getSpringGlassPane().setFaded(true);
			JOptionPane.showMessageDialog(this.mainScrollPane, 
						formatter.toString(), 
						title, 
						JOptionPane.ERROR_MESSAGE);
			pluginAdapter.getSpringGlassPane().setFaded(false);
		}
		
		return false;
	}
	
	public void openReview(File f) {
		if(!startMode) {
			ModeratorPlugin plugin = new ModeratorPlugin();
			plugin.openReviewOnRun(f);
			pluginAdapter.newPluginTab(plugin, true);
		} else {
			readReview(f);
		}
	}
	
	public void openReview() {
		final JFileChooser openDialog = new JFileChooser();
		openDialog.setMultiSelectionEnabled(false);
		
		openDialog.setFileFilter(new XMLFileFilter());
		
		pluginAdapter.getSpringGlassPane().setFaded(true);
		int ret = openDialog.showOpenDialog(mainScrollPane);
		pluginAdapter.getSpringGlassPane().setFaded(false);
			 
		if (JFileChooser.APPROVE_OPTION != ret)
			return;
				 
		File f = openDialog.getSelectedFile();
				 
		if (f.isFile() && f.canRead()) {
			openReview(f);
		}
	}
	
	public void newReview() {
		if(!startMode) {
			ModeratorPlugin plugin = new ModeratorPlugin();
			plugin.newReviewOnRun();
			pluginAdapter.newPluginTab(plugin, true);
		} else {
			reviewFile = null;
			pluginAdapter.setTitle(getLocalizedString("start.new_file"), 
					getLocalizedString("start.new_file"));
			setReview(null);
			setStartMode(false);
			setNextView();
		}
	}
	
	/**
	 * 
	 * @return true can be closed, otherwise false
	 */
	public boolean close() {
		if(!startMode) {
			String message = getLocalizedString("confirm.close");
			Formatter formatter = new Formatter();
			if(reviewFile == null)
				message = formatter.format(message, 
						getLocalizedString("start.new_file")).toString();
			else
				message = formatter.format(message, 
						reviewFile.getName()).toString();
			
			int option = JOptionPane.showConfirmDialog(mainScrollPane, 
					message, 
					getLocalizedString("confirm.close.title"), 
					JOptionPane.YES_NO_CANCEL_OPTION);
			
			switch(option) {
			case JOptionPane.CANCEL_OPTION:
				return false;
				
			case JOptionPane.NO_OPTION:
				return true;
				
			case JOptionPane.YES_OPTION:
				return saveReview();
			}
		}
		
		return true;
	}

	private class TabListener implements ListSelectionListener, Serializable {
		private static final long serialVersionUID = 8625863834513880068L;
		@Override
		public void valueChanged(ListSelectionEvent e) {
			updateView();
		}
	}
	
	private class NavigateToHomeAction extends AbstractAction {
		private static final long serialVersionUID = 6929810088727180600L;
		public NavigateToHomeAction() {
			putValue(Action.NAME, getLocalizedString("menu.home"));
		}
		@Override
		public void actionPerformed(ActionEvent e) {
			if(close()) {
				
				pluginAdapter.navigateToStartTab();
			}
		}
	}
	
	private class NextViewAction extends AbstractAction {
		private static final long serialVersionUID = -5051186228771979304L;
		@Override
		public void actionPerformed(ActionEvent e) {
			setNextView();
		}
	}
	
	private class PreviousViewAction extends AbstractAction {
		private static final long serialVersionUID = -5252028168971002171L;
		@Override
		public void actionPerformed(ActionEvent e) {
			setPreviousView();
		}
	}
	
	private class FirstViewAction extends AbstractAction {
		private static final long serialVersionUID = -6038555634600549846L;
		@Override
		public void actionPerformed(ActionEvent e) {
			setView(0);
		}
	}
	
	private class NewReviewAction extends AbstractAction {
		private static final long serialVersionUID = -3166264833164795793L;
		public NewReviewAction() {
			putValue(Action.NAME, getLocalizedString("menu.new"));
			
			KeyStroke ks = KeyStroke.getKeyStroke(KeyEvent.VK_N, 
					Toolkit.getDefaultToolkit().getMenuShortcutKeyMask());
			putValue(Action.ACCELERATOR_KEY, ks);
		}
		@Override
		public void actionPerformed(ActionEvent e) {
			newReview();
		}		
	}
	
	private class OpenReviewAction extends AbstractAction {
		private static final long serialVersionUID = -1349974230460227875L;
		public OpenReviewAction() {
			putValue(Action.NAME, getLocalizedString("menu.open"));
			
			KeyStroke ks = KeyStroke.getKeyStroke(KeyEvent.VK_O, 
					Toolkit.getDefaultToolkit().getMenuShortcutKeyMask());
			putValue(Action.ACCELERATOR_KEY, ks);
		}
		@Override
		public void actionPerformed(ActionEvent e) {
			openReview();
		}
	}
	
	private class OpenReviewFileAction extends AbstractAction {
		private static final long serialVersionUID = -2775189107743213015L;
		@Override
		public void actionPerformed(ActionEvent e) {
			openReview(startPanel.getHistoryFile());
		}
	}
	
	private class SaveReviewAction extends AbstractAction {
		private static final long serialVersionUID = -6895080742593347857L;
		public SaveReviewAction() {
			setEnabled(false);
			
			putValue(Action.NAME, getLocalizedString("menu.save"));
			
			KeyStroke ks = KeyStroke.getKeyStroke(KeyEvent.VK_S, 
					Toolkit.getDefaultToolkit().getMenuShortcutKeyMask());
			putValue(Action.ACCELERATOR_KEY, ks);
		}
		@Override
		public void actionPerformed(ActionEvent e) {
			saveReview();
		}		
	}
	
	private class SaveAsReviewAction extends AbstractAction {
		private static final long serialVersionUID = -8493350029946035608L;
		public SaveAsReviewAction() {
			setEnabled(false);
			
			putValue(Action.NAME, getLocalizedString("menu.save_as"));
		}
		@Override
		public void actionPerformed(ActionEvent e) {
			saveAsReview();
		}
	}
	
	private class OpenCatalogManagerAction extends AbstractAction {
		private static final long serialVersionUID = -7942612386381678798L;
		public OpenCatalogManagerAction() {
			putValue(Action.NAME, 
					getLocalizedString("menu.aspects.open_manager"));
			
			Icon largeIcon = new ImageIcon(getClass()
					.getResource("images/view-tree22.png"));
			Icon smallIcon = new ImageIcon(getClass()
					.getResource("images/view-tree_16.png"));
			
			putValue(Action.LARGE_ICON_KEY, largeIcon);
			putValue(Action.SMALL_ICON, smallIcon);
		}
		@Override
		public void actionPerformed(ActionEvent e) {
			pluginAdapter.getSpringGlassPane().setFaded(true);
			CatalogManager.showManagerDialog(mainScrollPane, 
					getCatalogWorkspace());
			pluginAdapter.getSpringGlassPane().setFaded(false);
			
			if(aspectsPanel != null) {
				aspectsPanel.readCatalogs();
			}
		}
	}
}